package com.pfdu.simplescheduler.schedule;

import com.pfdu.simplescheduler.common.Task;
import com.pfdu.simplescheduler.common.TaskStatus;
import com.pfdu.simplescheduler.config.SimpleSchedulerConfig;
import com.pfdu.simplescheduler.repo.TaskRepo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Slf4j
@Component
public class TaskResetSentinel {

    private Boolean shutdown = false;
    private Thread sentinel = new Thread(new Sentinel());

    @Autowired
    private TaskRepo taskRepo;

    @Autowired
    private SimpleSchedulerConfig config;

    //    @PostConstruct
    public void init() {
        sentinel.start();
    }

    /**
     * Sentinel 重置任务状态的巡逻兵
     * 1.查找执行超时的任务。
     * 2.检查任务是否属于当前节点处理，根据任务筛选策略，默认策略是乐观锁抢占机制。
     * 3.更新任务状态status为“未开始”、update_time 为当前时间、version = version+1。
     * 4.周期性睡眠。
     */
    class Sentinel implements Runnable {

        @Override
        public void run() {
            log.info("TaskResetSentinel is started.");
            while (!shutdown) {
                try {
                    // 1
                    List<Task> tasks = taskRepo.listTimeoutTasks(config.getTaskExecuteOutTime()); // 可配置项
                    Optional.ofNullable(tasks)
                            .orElse(new ArrayList<>(0))
                            .forEach(task -> {
                                log.info("TaskResetSentinel reset " + task.toString() + " now.");
                                // 2 检查，筛选策略（性能优化项目，但影响不大）
                                // @Todo
                                // 3
                                task.setStatus(TaskStatus.NOT_STARTED);
                                taskRepo.updateWithVersion(task);
                                log.info("TaskResetSentinel reset " + task.toString() + " successfully.");
                            });
                } catch (Exception e) {
                    log.error("TaskResetSentinel reset task failed", e);
                }
                // 4
                try {
                    Thread.sleep(config.getTaskResetPeriod()); // 可配置项
                } catch (InterruptedException e) {
                    log.warn("TaskResetSentinel is interrupted when sleeping.");
                }
            }
            log.info("TaskResetSentinel is stopped.");
        }
    }

    public void start() {
        init();
    }

    public void stop() {
        this.shutdown = true;
        sentinel.interrupt();
    }
}
